using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity.Core.Objects;
using System.Net;
using Framework.Interface;

namespace Framework
{
	/// <summary>
	/// This class provides simple formatting and display methods for 
	/// debugging purposes.
	/// </summary>
	public static class _
	{
        private static object aLock = new object();

        private static void WriteToConsole(string value)
        {
            lock(aLock)
            {
                Console.Write(value);
            }
        }

        /// <summary>
        /// Writes the line to console.
        /// </summary>
        /// <param name="value">The value.</param>
        private static void WriteLineToConsole(string value)
        {
            lock (aLock)
            {
                Console.WriteLine(value);
            }
        }

		#region P
		public static void P()
		{
			WriteLineToConsole("");
		}

		public static void P(string value)
		{
			WriteLineToConsole(value);
		}

		public static void P(WebResponse response)
		{
			WriteLineToConsole(WebUtil.ReadWebResponseToString(response));
		}
		public static void P(object value)
		{
            if (value == null)
            {
                WriteLineToConsole("null");
            }
			else if (value is ICollection)
			{
				foreach (object v in (ICollection)value)
				{
					if (v is IToXml)
					{
                        WriteLineToConsole(XmlUtil.StripXmlSchema(((IToXml)v).ToXml()));
					}
					else
					{
						WriteLineToConsole(v.ToString());
					}
				}
			}
            else if (value is ObjectQuery)
            {
                WriteLineToConsole(((ObjectQuery)value).ToTraceString());
            }
			else if (value is IToXml)
			{
				string xml = ((IToXml)value).ToXml();

                WriteLineToConsole(XmlUtil.StripXmlSchema(xml));
			}
			else
			{
				WriteLineToConsole(value.ToString());
			}
		}

		/// <summary>
		/// Write value to console using format string
		/// </summary>
		public static void P(string format, params object[] values)
		{
			WriteLineToConsole(format.FormatWith(values));
		}
        #endregion

        public static void Write(string value)
        {
            WriteToConsole(value);
        }
        public static void WriteLine(string value)
        {
            WriteLineToConsole(value);
        }

        #region FileContent
        public static void FileContent(string fileName)
        {
            _.P(FileUtil.Read(fileName));
        }
        #endregion

        #region X
		public static void X(object value)
		{
			X(value, true);
		}
		public static void X(object value, bool cleanXmlns)
		{
			if (value is IToXml)
			{
				P(CleanXmlns(((IToXml)value).ToXml(), cleanXmlns));
			}
			else
			{
				P(value);
			}
		}

		public static void X(object value, Type[] extraTypes)
		{
			X(value, extraTypes, true);
		}
		public static void X(object value, Type[] extraTypes, bool cleanXmlns)
		{
			if (value is IToXml)
			{
				P(CleanXmlns(((IToXml)value).ToXml(extraTypes), cleanXmlns));
			}
			else
			{
				P(value);
			}
		}
		#endregion

        #region Exception
        public static void Exception(Exception ex)
        {
            P(ExceptionUtil.Format(ex));
        }
        #endregion

        #region SerializeToFile
        public static void SerializeToFile(object value, string fileName)
        {
            XmlUtil.SerializeToFile(value, value.GetType(), fileName);
        }
        #endregion

        #region SerializeToString
        public static void SerializeToString(object value)
        {
            SerializeToString(value, true, string.Empty);
        }
        public static void SerializeToString(object value, string namespaceValue)
        {
            SerializeToString(value, true, namespaceValue);
        }

	    public static void SerializeToString(object value, bool cleanXmlns, string namespaceValue)
        {
            var xml = XmlUtil.SerializeToString(value);

            if (cleanXmlns)
            {
                xml = CleanXmlns(xml);
            }
	        if (Is.NotEmptyString(namespaceValue))
	        {
	            xml = XmlUtil.StripXmlNamespace(xml, namespaceValue);
	        }

            _.P(xml);
        }
        #endregion

        #region ObjectDump
        public static void ObjectDump(object value)
        {
            ObjectDumper.Write(value);
        }
        public static void ObjectDump(object value, int depth)
        {
            ObjectDumper.Write(value, depth);
        }
        #endregion

		#region CleanXmlns
		public static string CleanXmlns(IToXml xml)
		{
			return CleanXmlns(xml.ToXml(), true);
		}
		public static string CleanXmlns(string xml)
		{
			return CleanXmlns(xml, true);
		}
		public static string CleanXmlns(string xml, bool cleanXmlns)
		{
			string result = xml;
			
			if (cleanXmlns)
			{
                result = XmlUtil.StripXmlHeader(XmlUtil.StripXmlSchema(result));
			}

			return result;
		}
		#endregion

		#region Nv
		public static void Nv(string name, string value)
		{
			WriteLineToConsole(name.PadRight(30) + ": " + value);
		}

		public static void Nv(string name, int value)
		{
			WriteLineToConsole(name.PadRight(30) + ": " + value);
		}

		public static void Nv(string name, decimal value)
		{
			WriteLineToConsole(name.PadRight(30) + ": " + value);
		}

		public static void Nv(string name, bool value)
		{
			WriteLineToConsole(name.PadRight(30) + ": " + value);
		}
        
        public static void Nv(IDictionary<string, string> nameValues)
        {
            foreach (var key in nameValues.Keys)
            {
                Nv(key, nameValues[key]);
            }
        }
        #endregion

		#region L
		public static void L()
		{
		    L(100);
		}
		public static void L(int width)
		{
			WriteLineToConsole(StrUtil.Replicate(width, '-'));
		}
		public static void L(string heading)
		{
		    L(100, heading);
		}
		public static void L(int width, string heading)
		{
			string hd = "[ " + heading + " ]";

			WriteLineToConsole(hd.PadRight(width, '-'));
		}
		#endregion

        #region Replicate
        public static void Replicate(int len, char character)
        {
            WriteLineToConsole(StrUtil.Replicate(len, character));
        } 
        #endregion
    }
}
